from odoo import api, fields, models
from odoo.addons.rp_marketing_management.functions.marketing_record_and_operation_log_func import MarketingRecordAndOperationLogFunc
from odoo.exceptions import UserError, Warning
from ...functions.marketing_schedule_func import SCHEDULE_TYPE, MarketingScheduleFunc

SCHEDULE_STATE = [('draft', '草稿'), ('done', '完成'), ('discard', '弃用')]


class RpMarketingAutoSchedule(models.Model):
    _name = 'rp.marketing.auto.schedule'
    _description = '自动任务'

    code = fields.Char(string='序列号', default='RM_MST/****', copy=False, index=True)
    name = fields.Char(string='名称', copy=False, index=True)

    # 客户相关
    operation_person = fields.Many2one(string='操作人', comodel_name='res.users', default=lambda self: self.env.user, copy=False)
    is_category_tag = fields.Boolean(string='客户分类', copy=False, default=False, required=True)
    customer_category_ids = fields.Many2many(string='客户分类', comodel_name='rp.customer.category', column1='auto_schedule_id', column2='customer_category_id',
                                             relation='auto_schedule_customer_category_rel', copy=False)
    is_level_tag = fields.Boolean(string='客户等级', copy=False, default=False, required=True)
    customer_level_ids = fields.Many2many(string='客户等级', comodel_name='rp.customer.level', column1='auto_schedule_id', column2='customer_level_id',
                                          relation='auto_schedule_customer_level_rel', copy=False)
    fixed_customer_tag = fields.Boolean(string='指定用户', default=False, required=True, copy=False)
    rp_customer_ids = fields.Many2many(string='指定用户', comodel_name='rp.customer', column1='auto_schedule_id', column2='rp_customer_id'
                                       , relation='auto_schedule_rp_customer_rel', copy=False)
    schedule_type = fields.Selection(string='任务类型', selection=SCHEDULE_TYPE, default=SCHEDULE_TYPE[1][0], required=True, copy=False)

    # 优惠券和返现相关
    cash_back_tag = fields.Boolean(string='返现标志', copy=False, default=False)
    coupon_issue_tag = fields.Boolean(string='优惠券标志', copy=False, default=False)
    cash_back_price = fields.Float(string='返现', copy=False)
    currency_id = fields.Many2one(string='单位', comodel_name='res.currency', default=lambda self: self.env.company.currency_id, copy=False)
    coupon_line_display_ids = fields.Many2many(string='优惠券', comodel_name='rp.marketing.auto.coupon.issue.line', column1='auto_schedule_id',
                                               column2='auto_coupon_issue_line_id', relation='auto_schedule_and_coupon_issue_line_rel', compute='depends_auto_coupon_issue_line_ids', store=True, copy=False)
    auto_coupon_issue_line_ids = fields.One2many(string='优惠券明细', comodel_name='rp.marketing.auto.coupon.issue.line', inverse_name='auto_schedule_id', copy=False)
    schedule_state = fields.Selection(string='状态', selection=SCHEDULE_STATE, default='draft', copy=False)

    create_person = fields.Many2one(string='创建人', comodel_name='res.users', default=lambda self: self.env.user, copy=False)
    active_flag = fields.Boolean(string='有效', compute='depends_schedule_state', copy=False)

    @api.model_create_multi
    def create(self, vals_list):
        equal_ids = self.env['rp.marketing.auto.schedule']
        for vals in vals_list:
            vals['code'] = self.env['ir.sequence'].next_by_code('rp.marketing.auto.schedule') or '/'
            # 分类或等级标志未勾选并且指定用户未勾选，分类或等级默认为全部
            if not vals.get('is_category_tag') and not vals.get('fixed_customer_tag'):
                all_category_ids = self.env['rp.customer.category'].search([])
                vals['customer_category_ids'] = [(6, 0, all_category_ids.ids)]
            if not vals.get('is_level_tag') and not vals.get('fixed_customer_tag'):
                all_level_ids = self.env['rp.customer.level'].search([])
                vals['customer_level_ids'] = [(6, 0, all_level_ids.ids)]
            # 校验历史记录
            equal_id = MarketingScheduleFunc(self.env, self).handle_history_record(vals.get('code'), vals.get('fixed_customer_tag'), vals.get('rp_customer_ids')[0][2], vals.get('customer_level_ids')[0][2]
                                                                                   , vals.get('customer_category_ids')[0][2], vals.get('schedule_type'))
            equal_ids |= equal_id
        results = super(RpMarketingAutoSchedule, self).create(vals_list)
        # 失效一致的任务
        for equal_id in equal_ids:
            if len(equal_id) > 0:
                for record in equal_id:
                    record.write({'schedule_state': 'discard'})
        for result in results:
            result.write({'schedule_state': 'done'})
            result.generate_ir_cron()
        return result

    def name_get(self):
        res = []
        for record in self:
            name = record.get_name()
            res.append((record.id, name))
        return res

    def get_name(self):
        if self._context.get('show_code'):
            name = f'{self.name}({self.code})'
            return name
        return self.code

    @api.constrains('cash_back_tag', 'coupon_issue_tag', 'is_level_tag', 'is_category_tag', 'fixed_customer_tag')
    def _constrain_values(self):
        if not self.cash_back_tag and not self.coupon_issue_tag:
            raise UserError('请至少选择一种规则!')
        if self.cash_back_tag and self.cash_back_price <= 0:
            raise UserError('请填写有效金额!')
        if self.coupon_issue_tag and len(self.auto_coupon_issue_line_ids.ids) == 0:
            raise UserError('请添加优惠券!')

    @api.onchange('schedule_type')
    def onchange_schedule_type(self):
        if self.schedule_type == 'register':
            self.update({'is_category_tag': False, 'is_level_tag': False, 'fixed_customer_tag': False})

    @api.onchange('customer_level_ids', 'customer_category_ids')
    def onchange_category_level_tag(self):
        domain_list = []
        if len(self.customer_category_ids.ids) > 0:
            domain_list.append(('rp_customer_category', 'in', self.customer_category_ids.ids))
        if len(self.customer_level_ids.ids) > 0:
            domain_list.append(('customer_level', 'in', self.customer_level_ids.ids))
        self.update({'rp_customer_ids': False})
        return {'domain': {'rp_customer_ids': domain_list}}

    @api.onchange('is_level_tag', 'is_category_tag', 'fixed_customer_tag', 'coupon_issue_tag', 'cash_back_tag')
    def onchange_tag(self):
        if not self.is_category_tag:
            self.update({'customer_category_ids': False})
        if not self.is_level_tag:
            self.update({'customer_level_ids': False})
        if not self.fixed_customer_tag:
            self.update({'rp_customer_ids': False})
        if not self.coupon_issue_tag:
            self.update({'auto_coupon_issue_line_ids': False, 'coupon_line_display_ids': False})
        if not self.cash_back_tag:
            self.update({'cash_back_price': False})

    @api.depends('auto_coupon_issue_line_ids')
    def depends_auto_coupon_issue_line_ids(self):
        for record in self:
            if len(record.auto_coupon_issue_line_ids.ids) > 0:
                record.update({'coupon_line_display_ids': [(6, 0, record.auto_coupon_issue_line_ids.ids)]})

    @api.depends('schedule_state')
    def depends_schedule_state(self):
        for record in self:
            if record.schedule_state == 'draft':
                record.write({'active_flag': False})
            if record.schedule_state == 'discard':
                record.write({'active_flag': False})
            if record.schedule_state == 'done':
                record.write({'active_flag': True})

    def generate_ir_cron(self):
        if self.schedule_state == 'done':
            map_data = {}
            if self.schedule_type == 'birth':
                map_data = {
                    'name': f'{self.name}({self.code})',
                    'code': f'model.execute_birth_task({self.id})',
                    'interval_number': 1,
                    'interval_type': 'days',
                    'numbercall': -1,
                    'rp_marketing_auto_schedule_id': self.id,
                    'auto_schedule_tag': True
                }
                # 激活自动化任务
                MarketingScheduleFunc(self.env, self).active_auto_schedule(map_data)

    def turn_expired(self):
        """
        手动失效
        """
        self.ensure_one()
        self.write({'schedule_state': 'discard', 'active_flag': False})
        related_cron = self.env['ir.cron'].search([('rp_marketing_auto_schedule_id', '=', self.id)])
        related_cron.write({'active': False})

    def turn_enable(self):
        """
        手动启用
        """
        self.ensure_one()
        equal_ids = MarketingScheduleFunc(self.env, self).handle_history_record(self.code, self.fixed_customer_tag, self.rp_customer_ids.ids, self.customer_level_ids.ids, self.customer_category_ids.ids, self.schedule_type)
        # 处理自身以及关联信息
        self.write({'schedule_state': 'done'})
        # 注册自动任务由线程完成
        if self.schedule_type != 'register':
            related_cron = self.env['ir.cron'].search([('rp_marketing_auto_schedule_id', '=', self.id), ('active', '=', False)])
            related_cron.write({'active': True})
        # 处理与自身一致的记录
        if len(equal_ids) > 0:
            for record in equal_ids:
                record.write({'schedule_state': 'discard'})
                if record.schedule_type != 'register':
                    related_cron = self.env['ir.cron'].search([('rp_marketing_auto_schedule_id', '=', record.id), ('active', '=', True)])
                    related_cron.write({'active': False})

    def execute_birth_task(self, id):
        """
        生日定时任务的执行逻辑
        """
        schedule = self.env['rp.marketing.auto.schedule'].search([('id', '=', id)])
        domain_list = MarketingScheduleFunc(self.env, self).build_domain(schedule.customer_category_ids,
                                                                         schedule.customer_level_ids, schedule.rp_customer_ids)
        rp_customer_ids = self.env['rp.customer'].search(domain_list)
        today_date = fields.Date.today().strftime("%m-%d")
        issue_customers = rp_customer_ids.filtered(lambda r: r.birthday_date and r.birthday_date.strftime("%m-%d") == today_date)
        if len(issue_customers.ids) > 0:
            for customer in issue_customers:
                MarketingScheduleFunc(self.env, self).issue_coupon_and_cash(customer, schedule)
            # 记录任务日志
            MarketingScheduleFunc(self.env, self).record_the_schedule_log(customer_ids=issue_customers, price_change_type='add', cash_back_price=schedule.cash_back_price, coupon_issue_line_ids=schedule.auto_coupon_issue_line_ids, operation_type='auto',
                                                                          operation_person=schedule.operation_person, record_id=schedule.id)

    """
    默认定时任务执行逻辑
    """

    def coupon_rule_auto_task(self):
        """
        优惠券自动生效和过期
        """
        customer_coupons = self.env['rp.customer.coupon'].search([('rp_coupon_status', 'not in', ['used', 'expired'])])
        # 1 未生效的生效  2 未使用的到达期限的过期
        # 需要生效的优惠券
        to_active_coupons = customer_coupons.filtered(lambda r: r.rp_coupon_status == 'not_active' and r.customer_coupon_start_date <= fields.Date.today())
        if len(to_active_coupons.ids) > 0:
            for coupon in to_active_coupons:
                coupon.write({'rp_coupon_status': 'not_use'})
                # 生效记录
                MarketingRecordAndOperationLogFunc(self.env).create_coupon_log('active', coupon.rp_customer_id, coupon)
        # 需要过期的优惠券
        to_expired_coupons = customer_coupons.filtered(lambda r: r.rp_coupon_status == 'not_use' and r.customer_coupon_expired_date < fields.Date.today())
        if len(to_expired_coupons) > 0:
            for coupon in to_expired_coupons:
                coupon.write({'rp_coupon_status': 'expired'})
                # 过期记录
                MarketingRecordAndOperationLogFunc(self.env).create_coupon_log('expired', coupon.rp_customer_id, coupon)

    def coupon_template_auto_task(self):
        """
        优惠券模板自动任务
        """
        # 搜寻处于激活状态并结束时间已确定的记录
        coupon_template_ids = self.env['rp.marketing.coupon.template'].search([('state', '=', 'enable'), ('end_date', '!=', False)])
        to_expired_templates = coupon_template_ids.filtered(lambda r: r.end_date < fields.Date.today())
        for record in to_expired_templates:
            record.write({'state': 'expired'})

    def invite_rule_auto_expired(self):
        """
        邀请奖励规则自动失效
        """
        # 需要过期的规则
        reward_rules = self.env['rp.reward.incentive.rule'].search([('validate_flag', '=', True), ('end_date_validate', '<=', fields.Date.today())])
        for rule in reward_rules:
            rule.write({'validate_flag': False})

    def adjust_template_auto_validate_expired(self):
        """
        调价模板自动生效和过期
        """
        # 自动生效
        to_validate_template_ids = self.env['rp.marketing.adjust.price.template'].search([('template_state', '=', 'await_enable'), ('validate_time', '<=', fields.Date.today())])
        if len(to_validate_template_ids.ids) > 0:
            for record in to_validate_template_ids:
                record.write({'template_state': 'enable'})
            MarketingScheduleFunc(self.env, self).create_adjust_template_auto_validate_expired_log(to_validate_template_ids, True)
        # 自动过期
        to_expire_template_ids = self.env['rp.marketing.adjust.price.template'].search([('template_state', '=', 'enable'), ('expired_time', '<', fields.Date.today())])
        if len(to_expire_template_ids.ids) > 0:
            for record in to_expire_template_ids:
                record.write({'template_state': 'expired'})
            MarketingScheduleFunc(self.env, self).create_adjust_template_auto_validate_expired_log(to_expire_template_ids, False)

    def rp_invite_plan_auto_task(self):
        """
        邀请计划自动任务
        1 计划失效  2 相关联的任务失效（用户相关）
        """
        result_browser = self.env['rp.invite.plan'].browse()
        invite_plan_ids = self.env['rp.invite.plan'].search([])
        # NOTE 规则被手动弃用后，关联的邀请计划失效
        discard_plan_ids = invite_plan_ids.filtered(lambda r: r.rp_reward_incentive_rule_id.rule_state == 'discard')
        result_browser |= discard_plan_ids
        for record in discard_plan_ids:
            record.write({'plan_state': 'discard'})
        # NOTE 结束时间已过的进行规则失效
        expired_invite_plan_ids = invite_plan_ids.filtered(lambda r: r.validate_end_date <= fields.Date.today())
        result_browser |= expired_invite_plan_ids
        for record in expired_invite_plan_ids:
            record.write({'plan_state': 'discard'})
        # NOTE 已生成邀请码的用户的邀请任务失效
        for record in result_browser:
            customer_ids = record.generated_person_ids
            for item in customer_ids:
                discard_invite_task = item.invite_code_ids.filtered(lambda r: r.rp_reward_incentive_rule_id.invite_category_id.id == record.rp_reward_incentive_rule_id.invite_category_id.id)
                for data in discard_invite_task:
                    data.write({'validate_flag': False})


class RpMarketingAutoCouponIssueLine(models.Model):
    _name = 'rp.marketing.auto.coupon.issue.line'
    _description = '优惠券明细'

    auto_schedule_id = fields.Many2one(string='关联主表', comodel_name='rp.marketing.auto.schedule', copy=False)
    rp_coupon_template_id = fields.Many2one(string='优惠券模板', comodel_name='rp.marketing.coupon.template', copy=False)
    name_display = fields.Char(string='名称', compute='depends_template_amount', copy=False, store=True)
    amount = fields.Integer(string='数量', copy=False)

    def name_get(self):
        result = []
        for record in self:
            result.append((record.id, f'{record.rp_coupon_template_id.name} ✖ {str(record.amount)}'))
        return result

    @api.depends('rp_coupon_template_id', 'amount')
    def depends_template_amount(self):
        for record in self:
            if all([record.rp_coupon_template_id, record.amount]):
                record.write({'name_display': f'{record.rp_coupon_template_id.name}*{record.amount}'})
            else:
                record.write({'name_display': 'NEW'})
